package com.cx.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.converters.*;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.util.*;

public class BeanHelper {

    private BeanHelper() {
    }

    /**
     * 判断是否是简单值类型.包括：基础数据类型、CharSequence、Number、Date、URL、URI、Locale、Class;
     *
     * @param clazz
     * @return
     */
    public static boolean isSimpleValueType(final Class<?> clazz) {
        return (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() || CharSequence.class.isAssignableFrom(clazz)
                || Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || URI.class == clazz
                || URL.class == clazz || Locale.class == clazz || Class.class == clazz);
    }

    /**
     * findAll缓存key
     * @param keyspace
     * @param methodname
     * @param paramnames 第一个，第二个，...依次排列
     * @param paramvals 第一个，第二个，...依次排列，和paramnames的顺序一致
     * @return
     */
    public static String key(final String keyspace, final String methodname, final String[] paramnames, final Object[] paramvals){
        final StringBuffer sb = new StringBuffer(String.valueOf(keyspace));
        sb.append(":finds").append(StringUtils.isBlank(methodname)? "" : CacheConsts.SP + methodname);
        if(ArrayUtils.isNotEmpty(paramnames) && ArrayUtils.isNotEmpty(paramvals)) {
            Arrays.stream(paramnames).filter(p->null!=p).forEach(fieldname -> {
                sb.append(CacheConsts.SP+fieldname);
            });

            Arrays.stream(paramvals).filter(p->null!=p).forEach(paramval -> {
                if (paramval instanceof List) {
                    Collections.sort((List) paramval);
                }else if (paramval instanceof Object[]) {
                    Arrays.sort((Object[]) paramval);
                }else if(paramval instanceof Sort){
                    paramval = new String(ProtoStuffUtil.serialize(paramval));
                }
                sb.append(CacheConsts.SP + paramval.hashCode());
            });
        }

        return sb.toString();
    }

    public static <S> String getClassName(final Iterable<S> entities){
        return entities.iterator().next().getClass().getSimpleName().toLowerCase();
    }

    public static <S> Class<S> getClassGenericityParam(final Example<S> example){
        final Type genType = example.getClass().getGenericSuperclass();
        final Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        return (Class<S>)params[0];
    }

    public static JSONObject register(){

        return new JSONObject(true);
    }

    public static <T> Map<String, Object> toHash(final T t){

        return register().parseObject(JsonHelper.serialize(t), new TypeReference<Map<String,Object>>(){});
    }

    public static <T> T fromHash(final Map<String,Object> map, final Class<T> clazz){

        return register().fluentPutAll(map).toJavaObject(clazz);
    }
}